package org.artofsolving.jodconverter.office;

import java.net.ConnectException;

/**
 * {@link OfficeManager} implementation that connects to an external Office process.
 * <p>
 * The external Office process needs to be started manually, e.g. from the command line with
 * 
 * <pre>
 * soffice -accept="socket,host=127.0.0.1,port=2002;urp;"
 * </pre>
 * <p>
 * Since this implementation does not manage the Office process, it does not support auto-restarting the process if it
 * exits unexpectedly.
 * <p>
 * It will however auto-reconnect to the external process if the latter is manually restarted.
 * <p>
 * This {@link OfficeManager} implementation basically provides the same behaviour as JODConverter 2.x, including using
 * <em>synchronized</em> blocks for serialising office operations.
 */
class ExternalOfficeManager implements OfficeManager {

    private final OfficeConnection connection;
    private final boolean connectOnStart;

    /**
     * @param unoUrl
     * @param connectOnStart
     *            should a connection be attempted on {@link #start()}? Default is <em>true</em>. If <em>false</em>, a
     *            connection will only be attempted the first time an {@link OfficeTask} is executed.
     */
    public ExternalOfficeManager(UnoUrl unoUrl, boolean connectOnStart) {
        connection = new OfficeConnection(unoUrl);
        this.connectOnStart = connectOnStart;
    }

    @Override
    public void start() throws OfficeException {
        if (connectOnStart) {
            synchronized (connection) {
                connect();
            }
        }
    }

    @Override
    public void stop() {
        synchronized (connection) {
            if (connection.isConnected()) {
                connection.disconnect();
            }
        }
    }

    @Override
    public void execute(OfficeTask task) throws OfficeException {
        synchronized (connection) {
            if (!connection.isConnected()) {
                connect();
            }
            task.execute(connection);
        }
    }

    private void connect() {
        try {
            connection.connect();
        } catch (ConnectException connectException) {
            throw new OfficeException("could not connect to external office process", connectException);
        }
    }

    @Override
    public boolean isRunning() {
        return connection.isConnected();
    }

}
